package resolver

import (
	"context"

	"mall/service/wpgql/api/internal/graph/generated"
	"mall/service/wpgql/api/internal/graph/storage"
	"mall/service/wpgql/api/internal/svc"

	"github.com/99designs/gqlgen/graphql"
)

// This file will not be regenerated automatically.
//
// It serves as dependency injection for your app, add any dependencies you require here.

type Resolver struct {
	// storage is an interface for reading/writing to the datastore
	storage storage.Storage
	svcCtx  *svc.ServiceContext
}

// NewResolver returns a Resolver
func NewResolver(svcCtx *svc.ServiceContext) *Resolver {
	return &Resolver{
		storage: svcCtx.Storage,
		svcCtx:  svcCtx,
	}
}

type ckey string

func NewDirective() generated.DirectiveRoot {
	return generated.DirectiveRoot{
		User: func(ctx context.Context, obj interface{}, next graphql.Resolver, username string) (res interface{}, err error) {
			return next(context.WithValue(ctx, ckey("username"), username))
		},
		IsAuthenticated: func(ctx context.Context, obj interface{}, next graphql.Resolver) (interface{}, error) {
			// if exist := auth.ExistsInContext((ctx)); !exist {
			// 	return nil, fmt.Errorf("Access denied")
			// }
			return next(ctx)
		},
		// HasRole: func(ctx context.Context, obj interface{}, next graphql.Resolver, roles []RoleLevel, level ActionLevel, typeArg ObjectType) (res interface{}, err error) {
		// 	userID, ok := GetUser(ctx)
		// 	if !ok {
		// 		return nil, errors.New("user must be logged in")
		// 	}
		// 	user, err := repo.GetUserAccountByID(ctx, userID)
		// 	if err != nil {
		// 		return nil, err
		// 	}
		// 	if user.RoleCode == "admin" {
		// 		return next(ctx)
		// 	} else if level == ActionLevelOrg {
		// 		return nil, errors.New("must be an org admin")
		// 	}

		// 	var subjectID uuid.UUID
		// 	in := graphql.GetFieldContext(ctx).Args["input"]
		// 	val := reflect.ValueOf(in) // could be any underlying type
		// 	if val.Kind() == reflect.Ptr {
		// 		val = reflect.Indirect(val)
		// 	}
		// 	var fieldName string
		// 	switch typeArg {
		// 	case ObjectTypeTeam:
		// 		fieldName = "TeamID"
		// 	case ObjectTypeTask:
		// 		fieldName = "TaskID"
		// 	case ObjectTypeTaskGroup:
		// 		fieldName = "TaskGroupID"
		// 	case ObjectTypeTaskChecklist:
		// 		fieldName = "TaskChecklistID"
		// 	case ObjectTypeTaskChecklistItem:
		// 		fieldName = "TaskChecklistItemID"
		// 	default:
		// 		fieldName = "ProjectID"
		// 	}
		// 	logger.New(ctx).WithFields(log.Fields{"typeArg": typeArg, "fieldName": fieldName}).Info("getting field by name")
		// 	subjectField := val.FieldByName(fieldName)
		// 	if !subjectField.IsValid() {
		// 		logger.New(ctx).Error("subject field name does not exist on input type")
		// 		return nil, errors.New("subject field name does not exist on input type")
		// 	}
		// 	if fieldName == "TeamID" && subjectField.IsNil() {
		// 		// Is a personal project, no check
		// 		// TODO: add config setting to disable personal projects
		// 		return next(ctx)
		// 	}
		// 	subjectID, ok = subjectField.Interface().(uuid.UUID)
		// 	if !ok {
		// 		logger.New(ctx).Error("error while casting subject UUID")
		// 		return nil, errors.New("error while casting subject uuid")
		// 	}

		// 	if level == ActionLevelProject {
		// 		logger.New(ctx).WithFields(log.Fields{"subjectID": subjectID}).Info("fetching subject ID by typeArg")
		// 		if typeArg == ObjectTypeTask {
		// 			subjectID, err = repo.GetProjectIDForTask(ctx, subjectID)
		// 		}
		// 		if typeArg == ObjectTypeTaskGroup {
		// 			subjectID, err = repo.GetProjectIDForTaskGroup(ctx, subjectID)
		// 		}
		// 		if typeArg == ObjectTypeTaskChecklist {
		// 			subjectID, err = repo.GetProjectIDForTaskChecklist(ctx, subjectID)
		// 		}
		// 		if typeArg == ObjectTypeTaskChecklistItem {
		// 			subjectID, err = repo.GetProjectIDForTaskChecklistItem(ctx, subjectID)
		// 		}
		// 		if err != nil {
		// 			logger.New(ctx).WithError(err).Error("error while getting subject ID")
		// 			return nil, err
		// 		}
		// 		projectRoles, err := GetProjectRoles(ctx, repo, subjectID)
		// 		if err != nil {
		// 			if err == sql.ErrNoRows {
		// 				return nil, &gqlerror.Error{
		// 					Message: "not authorized",
		// 					Extensions: map[string]interface{}{
		// 						"code": "401",
		// 					},
		// 				}
		// 			}
		// 			logger.New(ctx).WithError(err).Error("error while getting project roles")
		// 			return nil, err
		// 		}
		// 		for _, validRole := range roles {
		// 			logger.New(ctx).WithFields(log.Fields{"validRole": validRole}).Info("checking role")
		// 			if CompareRoleLevel(projectRoles.TeamRole, validRole) || CompareRoleLevel(projectRoles.ProjectRole, validRole) {
		// 				logger.New(ctx).WithFields(log.Fields{"teamRole": projectRoles.TeamRole, "projectRole": projectRoles.ProjectRole}).Info("is team or project role")
		// 				return next(ctx)
		// 			}
		// 		}
		// 		return nil, &gqlerror.Error{
		// 			Message: "not authorized",
		// 			Extensions: map[string]interface{}{
		// 				"code": "401",
		// 			},
		// 		}
		// 	} else if level == ActionLevelTeam {
		// 		role, err := repo.GetTeamRoleForUserID(ctx, storage.GetTeamRoleForUserIDParams{UserID: userID, TeamID: subjectID})
		// 		if err != nil {
		// 			logger.New(ctx).WithError(err).Error("error while getting team roles for user ID")
		// 			return nil, err
		// 		}
		// 		for _, validRole := range roles {
		// 			if CompareRoleLevel(role.RoleCode, validRole) || CompareRoleLevel(role.RoleCode, validRole) {
		// 				return next(ctx)
		// 			}
		// 		}
		// 		return nil, &gqlerror.Error{
		// 			Message: "not authorized",
		// 			Extensions: map[string]interface{}{
		// 				"code": "401",
		// 			},
		// 		}

		// 	}
		// 	return nil, &gqlerror.Error{
		// 		Message: "bad path",
		// 		Extensions: map[string]interface{}{
		// 			"code": "500",
		// 		},
		// 	}
		// },
	}
}
